package com.liao.badminton.code;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSON;
import com.liao.badminton.context.BaseContextHandler;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Auther: liaocheng
 * @Date: 2020/8/30 23:13
 * @Description: 监察接口请求参数 ，和返回值
 */
@Aspect
@Component
public class LoggerAspect {
    @Value("${spring.application.name}")
    private String serverName;

    @Pointcut("execution(public * com.liao.badminton.controller.*Controller.*(..))")
    public void logAspect() {
    }

    public Map<String, Logger> mapLog = MapUtil.newConcurrentHashMap();

    @Around("logAspect()")
    public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        ResponseRest response = ResponseRest.fail( BaseContextHandler.getOption());
        String name = joinPoint.getSignature().getName();
        Logger targetLogger = getLogger(joinPoint);
        Object[] args = joinPoint.getArgs();
        Stream<?> stream = ArrayUtil.isEmpty(args) ? Stream.empty() : Arrays.stream(args);
        List<Object> logArgs = stream.filter(arg -> !(arg instanceof MultipartFile[]) && !(arg instanceof MultipartFile) && !(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse))
                .collect(Collectors.toList());
        long startTime = System.currentTimeMillis();
        targetLogger.info("start invoking {} , param is  {}", name, JSON.toJSONString(logArgs));
        try {
            Object data = joinPoint.proceed();
            if (data != null && data instanceof ResponseRest) {
                response = (ResponseRest) data;
            } else if (!(data instanceof ResponseRest)) {
                response.setData(data);
            }
            if (!response.getSuc()) {

            }
//            response.setOpe(name);
        } catch (ProjectException e) {
            targetLogger.error("error {}", e);
            response = response.setCodeAndMsg(e.getCode(), e.getMessage());
        } catch (MethodArgumentNotValidException e) {
            targetLogger.error("error {}", e);
            response = response.setRespCodeMessage(RespCodeMessage.PARAM_ERROR).setMsg(e.getMessage());
        } catch (Exception e) {
//            targetLogger.error("LoggerAspect -------error {}", e);
            throw e;
        }
        long endTime = System.currentTimeMillis();
        targetLogger.info("finish invoked {},response is {} expend time is: {} ", name, JSON.toJSONString(response), endTime - startTime);
        String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
        mapLog.remove(declaringTypeName);
        return response;
    }

    private Logger getLogger(JoinPoint joinPoint) {
        String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
        if (!mapLog.containsKey(declaringTypeName)) {
            Class declaringType = joinPoint.getSignature().getDeclaringType();
            Logger targetLogger = LoggerFactory.getLogger(declaringType);
            mapLog.put(declaringTypeName, targetLogger);
            return targetLogger;
        } else {
            return mapLog.get(declaringTypeName);
        }

    }
}